#define _CRT_SECURE_NO_WARNINGS 1

import numpy as np
import pandas as pd
from pandas import DataFrame
from scipy.interpolate import interp1d
from.min_factor import MinFactor

class MF_SNR(MinFactor) :
    def __init__(self, save_dir: str) :
    super().__init__('SignalNoiseRatio', save_dir)

    def operator(self, stock_data: DataFrame) :
    if stock_data.empty or stock_data.isnull().all().all() or stock_data['Close'].nunique() == 1 :
        snr = np.nan
    else :
        signal = stock_data['Close'].values
        print(signal)
        imfs = self.emd(signal)
        if len(imfs) == 0 :
            snr = np.nan
            noise = imfs[0]
            signal = np.sum(imfs[1:], axis = 0)
            power_signal = np.mean(signal * *2)
            power_noise = np.mean(noise * *2)
            if power_noise == 0:
snr = np.inf
            else:
snr = np.log10(power_signal / power_noise)
print(snr)
return snr

def emd(self, signal, max_imfs = 10) :
    imfs = []
    residue = signal
    for _ in range(max_imfs) :
        imf = self.extract_imf(residue)
        imfs.append(imf)
        residue = residue - imf
        if np.all(residue == 0) :
            break
            return imfs

            def extract_imf(self, signal) :
            h = signal
            while not self.is_imf(h) :
                peaks = np.where((np.diff(np.sign(np.diff(h))) < 0))[0] + 1
                troughs = np.where((np.diff(np.sign(np.diff(h))) > 0))[0] + 1
                if len(peaks) < 2 or len(troughs) < 2 :
                    return h
                    upper_env = self.linear_interpolate(peaks, h[peaks], np.arange(len(h)))
                    lower_env = self.linear_interpolate(troughs, h[troughs], np.arange(len(h)))
                    mean_env = (upper_env + lower_env) / 2
                    h = h - mean_env
                    return h

                    def is_imf(self, x) :
                    N = len(x)
                    num_extrema = np.sum((np.diff(np.sign(np.diff(x))) != 0).astype(int))
                    num_zero_crossings = np.sum(np.diff(np.sign(x)) != 0)
                    return abs(num_extrema - num_zero_crossings) <= 1

                    def linear_interpolate(self, x, y, xi) :
                    yi = np.interp(xi, x, y)
                    return yi